﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Linq;
using Tamir.SharpSsh;
namespace Librerias
{
    public class ObjetoAd : System.DirectoryServices.DirectoryEntry
    {

        #region Propiedades

        private static string passPhrase = "Pas5pr@se";        // can be any string
        private static string saltValue = "s@1tValue";        // can be any string
        private static string hashAlgorithm = "SHA1";             // can be "MD5"
        private static int passwordIterations = 2;                  // can be any number
        private static string initVector = "@1B2c3D4e5F6g7H8"; // must be 16 bytes
        private static int keySize = 256;                // can be 192 or 128

        private System.DirectoryServices.DirectoryEntry _de;
        private readonly string _rutaAd = Configuracion.Get("rutaAD"); // tiene ademas del host.. /dc=tierradelfuego,dc=gov,dc=ar
        private readonly string _path_ad = Configuracion.Get("ad_path");
        private readonly string _userAd = Configuracion.Get("userAD");
        private readonly string _passAd = Encriptador.Decrypt(Configuracion.Get("passAD"), passPhrase,
                                            saltValue,
                                            hashAlgorithm,
                                            passwordIterations,
                                            initVector,
                                            keySize);

        private readonly string _sufijoMail = Configuracion.Get("dominio");
        public const int NormalAccount = 0x0200;
        public const int DontExpirePassword = 0x10000;
        public const int PasswordExpired = 0x800000;




        #endregion

        #region Constructores
        public ObjetoAd()
        {
            _de = new System.DirectoryServices.DirectoryEntry(_rutaAd, _userAd, _passAd, AuthenticationTypes.Secure);

            if (_de.SchemaClassName == "domainDNS")
            {
                _sufijoMail = _de.Properties["distinguishedName"].Value.ToString().Replace("DC=", "").Replace(",", ".");
            }
        }
        private ObjetoAd(System.DirectoryServices.DirectoryEntry directoryEntry)
        {
            _de = directoryEntry;
            /*
            if (_de.SchemaClassName == "domainDNS")
            {
                _sufijoMail = _de.Properties["distinguishedName"].Value.ToString().Replace("DC=", "").Replace(",", ".");
            }
             */
        }
        public ObjetoAd(string path)
        {
            _de = new System.DirectoryServices.DirectoryEntry(path, _userAd, _passAd, System.DirectoryServices.AuthenticationTypes.Secure);
        }
        public ObjetoAd(string user, string pass)
        {
            try
            {
                _de = new DirectoryEntry(_rutaAd, user, pass, AuthenticationTypes.Secure);
                var search = new System.DirectoryServices.DirectorySearcher(_de) { Filter = String.Format("(sAMAccountName={0})", user) };
                SearchResult resultado = search.FindOne();
                _de = new DirectoryEntry(resultado.Path, _userAd, _passAd, AuthenticationTypes.Secure);
            }
            catch (Exception ex)
            {
                Notificaciones.Error(ex.Message);
                _de = null;
                //throw;
            }

            
            //_de = new DirectoryEntry(_rutaAd, _userAd, _passAd, AuthenticationTypes.Secure);

            
            //adsSearcher.Filter = "(&(objectClass=user)(objectCategory=person))";

            
        }
        #endregion

        #region Propiedades
        public DirectoryEntry DirectoryEntry
        {
            get
            {
                return _de;
            }
        }
        public bool EsAdmin
        {
            get
            {
                foreach (string path in _de.Properties["memberOf"])
                {
                    if (path == "CN=_GP_US_ADMINS,OU=GROUPS,DC=domtdf,DC=local") return true;
                }
                return false;

            }
        }
        public object AdGuid
        {
            get
            {
                return _de.Properties.Contains("objectGUID") ? _de.Properties["objectGUID"].Value : null;
            }
        }

        public string SamAccountName
        {
            get
            {
                return _de.Properties.Contains("samAccountName") ? _de.Properties["samAccountName"].Value.ToString() : null;
            }
            set
            {
                _de.Properties["samAccountName"].Value = value;
                _de.CommitChanges();
            }
        }
        public string Nombre
        {
            get
            {
                return _de.Properties.Contains("givenName") ? _de.Properties["givenName"].Value.ToString() : null;
            }

            set
            {
                _de.Properties["givenName"].Value = value.ToUpper();
                _de.CommitChanges();
            }
        }
        public string Apellido
        {
            get
            {
                return _de.Properties.Contains("SN") ? _de.Properties["SN"].Value.ToString() : null;
            }
            set
            {
                _de.Properties["SN"].Value = value.ToUpper();
                _de.CommitChanges();
            }
        }
        public string DNI {
            get
            {
                return _de.Properties.Contains("info") ? _de.Properties["info"].Value.ToString() : null;
            }
            set
            {
                _de.Properties["info"].Value = value.ToUpper();
                _de.CommitChanges();
            }
        }
        public string DisplayName
        {
            get
            {
                return _de.Properties.Contains("displayName") ? _de.Properties["displayName"].Value.ToString() : null;
            }
            set
            {
                _de.Properties["displayName"].Value = value.ToUpper();
                _de.CommitChanges();
            }
        }
        public string Mail
        {
            get
            {
                //return _de.Properties.Contains("mail") ? _de.Properties["mail"].Value.ToString() : null;
                return SamAccountName + "@tierradelfuego.gov.ar";

                //return _de.Properties["mail"].Value.ToString();
            }
            set
            {
                _de.Properties["mail"].Value = value + "@" + _sufijoMail;
                _de.CommitChanges();
            }
        }
        /// <summary>
        ///   Guarda el usuario + el mail. Ej: nchavez@tierradelfuego.gov.ar
        /// </summary>
        public string UserPrincipalName
        {
            get
            {
                return _de.Properties.Contains("userPrincipalName") ? _de.Properties["userPrincipalName"].Value.ToString() : null;
            }
            set
            {
                _de.Properties["userPrincipalName"].Value = value + "@" + _sufijoMail;
                _de.CommitChanges();
            }
        }
        public string UserPassword
        {
            set
            {

                _de.Invoke("SetPassword", new object[] { value });
                _de.CommitChanges();
            }
        }
        public int UserFlags
        {
            get
            {
                return _de.Properties.Contains("userAccountControl") ? int.Parse(_de.Properties["userAccountControl"].Value.ToString()) : 0;

            }
            set
            {
                _de.Properties["userAccountControl"].Value = value;
                _de.CommitChanges();
            }
        }
        public string MsSfu30Name
        {
            get
            {
                return _de.Properties.Contains("msSFU30Name") ? _de.Properties["msSFU30Name"].Value.ToString() : null;
            }
            set
            {
                _de.Properties["msSFU30Name"].Value = value;
                _de.CommitChanges();
            }
        }
        public string NisDomain
        {
            get
            {
                return _de.Properties.Contains("msSFU30NisDomain") ? _de.Properties["msSFU30NisDomain"].Value.ToString() : null;
            }
            set
            {
                _de.Properties["msSFU30NisDomain"].Value = value;
                _de.CommitChanges();
            }
        }
        public int UidNumber
        {
            get
            {
                return _de.Properties.Contains("uidNumber") ? int.Parse(_de.Properties["uidNumber"].Value.ToString()) : 0;
            }
            set
            {
                _de.Properties["uidNumber"].Value = value;
                _de.CommitChanges();
            }
        }
        public string Uid
        {
            get
            {
                return _de.Properties.Contains("uid") ? _de.Properties["uid"].Value.ToString() : null;
            }
            set
            {
                _de.Properties["uid"].Value = value;
                _de.CommitChanges();
            }
        }
        public int GidNumber
        {
            get
            {
                return _de.Properties.Contains("gidNumber") ? int.Parse(_de.Properties["gidNumber"].Value.ToString()) : 0;
            }
            set
            {
                _de.Properties["gidNumber"].Value = value;
                _de.CommitChanges();
            }
        }
        public string LoginShell
        {
            get
            {
                return _de.Properties.Contains("loginShell") ? _de.Properties["loginShell"].Value.ToString() : "/bin/sh";
            }
            set
            {
                _de.Properties["loginShell"].Value = value;
                _de.CommitChanges();
            }
        }
        public string HomeDirectory
        {
            get
            {
                return _de.Properties.Contains("unixHomeDirectory") ? _de.Properties["unixHomeDirectory"].Value.ToString() : "/homes/" + SamAccountName;
            }
            set
            {
                _de.Properties["unixHomeDirectory"].Value = value;
                _de.CommitChanges();
            }
        }

        public int PwdLastSet
        {
            set
            {
                _de.Properties["pwdLastSet"].Value = value;
                _de.CommitChanges();
            }
        }

        public string fechaCreacion {
            get
            {
                return _de.Properties["whenCreated"].Value.ToString();
            }
        }

        #endregion

        #region Metodos Publicos
        public ObjetoAd NuevoHijo(string name, string schema)
        {
            DirectoryEntry nuevoHijo = _de.Children.Add(name, schema);
            return new ObjetoAd(nuevoHijo);
        }
        public SearchResultCollection Buscar(string str)
        {
            using (var deSearch = new DirectorySearcher())
            {
                deSearch.SearchRoot = _de;
                deSearch.Filter = String.Format("(&(objectClass=user)(|(displayName=*{0}*)(SAMAccountName={0})(info=*{0}*)))", str);
                deSearch.SearchScope = SearchScope.Subtree;
                SearchResultCollection results = deSearch.FindAll();

                return results;
            }
        }

        public SearchResultCollection BuscarSinNis()
        {
            using (var deSearch = new DirectorySearcher())
            {
                deSearch.SearchRoot = _de;
                deSearch.Filter = String.Format("(&(objectClass=user)(!(msSFU30NisDomain=*)))");
                deSearch.SearchScope = SearchScope.Subtree;
                deSearch.PageSize = 1000;
                SearchResultCollection results = deSearch.FindAll();
                
                return results;
            }
        }

        public SearchResultCollection BuscarSinUid()
        {
            using (var deSearch = new DirectorySearcher())
            {
                deSearch.SearchRoot = _de;
                deSearch.Filter = String.Format("(&(objectClass=user)(!(uid=*)))");
                deSearch.SearchScope = SearchScope.Subtree;
                deSearch.PageSize = 1000;
                SearchResultCollection results = deSearch.FindAll();

                return results;
            }
        }

        public SearchResultCollection BuscarUidDuplicados()
        {
            using (var deSearch = new DirectorySearcher())
            {
                deSearch.SearchRoot = _de;
                deSearch.Filter = String.Format("(&(objectClass=user)(uidNumber=11090))");
                deSearch.SearchScope = SearchScope.Subtree;
                deSearch.PageSize = 1000;
                SearchResultCollection results = deSearch.FindAll();

                return results;
            }
        }
        public bool Login()
        {
            if (EsAdmin)
                return true;
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="str">Ldap Path</param>
        public void GetObjeto(string str)
        {
            _de = new DirectoryEntry(str, _userAd, _passAd, AuthenticationTypes.Secure);
        }
        public void GetObjeto(Guid guid)
        {
            _de = new DirectoryEntry(_path_ad + "/<GUID=" + guid + ">", _userAd, _passAd);
        }
        public IEnumerable<SearchResult> GetGrupos()
        {
            using (var deSearch = new DirectorySearcher(_de))
            {
                //deSearch.Filter = "(&(objectClass=group)(gidNumber=*))";
                deSearch.Filter = "(objectClass=group)";
                deSearch.SearchScope = SearchScope.Subtree;


                SearchResultCollection results = deSearch.FindAll();
                if (results.Count > 0)
                {
                    foreach (SearchResult item in results)
                    {
                        yield return item;
                    }
                }
            }

        }

        public IEnumerable<ObjetoAd> GetUsuarios()
        {
            using (var deSearch = new DirectorySearcher(_de))
            {
                deSearch.Filter = "(&(objectClass=user)(mail=*))";
                deSearch.SearchScope = SearchScope.Subtree;
                deSearch.PageSize = 1000;

                SearchResultCollection results = deSearch.FindAll();
                if (results.Count > 0)
                {
                    foreach (SearchResult item in results)
                    {
                        yield return new ObjetoAd(item.Path);
                    }
                }

            }
        }

        public void SetUltimoUid()
        {
            using (var ad = new ObjetoAd())
            {
                var sr = new DirectorySearcher(ad.DirectoryEntry)
                             {
                                 Filter = "(uidNumber=*)",
                                 SearchScope = SearchScope.Subtree,
                                 PageSize = 1000
                             };
                //sr.Sort = new SortOption("UidNumber", SortDirection.Ascending);
                SearchResultCollection src = sr.FindAll();
                int ultimoUidActual = new ObjetoAd(src[src.Count - 1].Path).UidNumber;
                int ultimoUid = ultimoUidActual + 1;
                UidNumber = ultimoUid;
            }
        }

        public static ArrayList EnumerateDomains()
        {
            var alDomains = new ArrayList();
            Forest currentForest = Forest.GetCurrentForest();
            DomainCollection myDomains = currentForest.Domains;

            foreach (Domain objDomain in myDomains)
            {
                alDomains.Add(objDomain.Name);
            }
            return alDomains;
        }



        public void Deshabilitar()
        {
            try
            {
                int val = (int)_de.Properties["userAccountControl"].Value;
                _de.Properties["userAccountControl"].Value = val | 0x2;
                
            }
            catch (Exception)
            {

                throw;
            }
        }

        public void Habilitar()
        {
            try
            {
                int val = (int)_de.Properties["userAccountControl"].Value;
                _de.Properties["userAccountControl"].Value = val & ~0x2;

            }
            catch (Exception)
            {

                throw;
            }
        }

        public bool Eliminar()
        {
            try
            {
                DirectoryEntry ou = _de.Parent;
                ou.Children.Remove(_de);
                ou.CommitChanges();
                return true;
            }
            catch (Exception)
            {
                return false;
                #endregion
            }
        }   
        public void Guardar()
        {
            try
            {
                _de.CommitChanges();
            }
            catch (UnauthorizedAccessException ex)
            {
                Notificaciones.Error(ex.Message);
            }
            
        }

        public bool CrearHome()
        {
            SshExec exec = new SshExec("10.1.9.219", "root");
            exec.Password = "Pa$$word99";
            Console.Write("Connecting...");
            exec.Connect();
            Console.WriteLine("OK");
            exec.RunCommand("mkdir /homes/" + this.SamAccountName);
            exec.RunCommand("chmod 700 /homes/" + this.SamAccountName);
            exec.RunCommand("chown " + this.UidNumber + ":" + this.GidNumber + " /homes/" + this.SamAccountName);
            return true;
        }

        public void ForzarCambioDePassword()
        {
            this.PwdLastSet = 0;
        }
    }



}
